//    Copyright (C) Kherty.  All rights reserved.
using System;

namespace OpenLS.Core
{
    public struct Fraction
    {
        public Fraction(int intPart, int num, int denominator)
        {
            if (denominator == 0)
                throw new ArgumentException("denominator");
            integerPart = intPart;
            numerator = num;
            this.denominator = denominator;
        }
        public static bool TryParse(string s, out Fraction f)
        {
            s = s.Trim();
            f = new Fraction();
            int spaceIndex = s.IndexOf(' ');
            int divideIndex = s.IndexOf('/');
            if (divideIndex < spaceIndex)
                return false;
            int integerPart;
            if (divideIndex == -1)
            {
                if (int.TryParse(s,out  integerPart))
                {
                    f = new Fraction {integerPart = integerPart, denominator = 1};
                    return true;
                }
                return false;
            }
            string[] ss = s.Split('/');
            if (ss.Length != 2)
                return false;
            string denominatorString = ss[1];
            int denominator;
            if (!int.TryParse(denominatorString, out denominator))
                return false;
            string integerPartString = null;
            string numeratorPart;

            if (spaceIndex >= 0)
            {
                ss = ss[0].Split(' ');
                if (ss.Length != 2)
                    return false;
                integerPartString = ss[0];
                numeratorPart = ss[1];

            }
            else
                numeratorPart = ss[0];
            int numerator;
            if (!int.TryParse(numeratorPart, out numerator))
                return false;
            integerPart = 0;
            if (integerPartString != null)
            {
                if (!int.TryParse(integerPartString, out integerPart))
                    return false;

            }
            f = new Fraction();
            f.integerPart = integerPart;
            f.numerator = numerator;
            f.denominator = denominator;
            return true;

        }
        public static Fraction Calculate (double value, int denominator)
        {
            Fraction result = new Fraction {IntegerPart = (int) Math.Floor(value)};
            double dbl1 = (value - result.IntegerPart) * denominator;
            result.Denominator = denominator;
            result.Numerator = (int)Math.Round(dbl1);
            return result;
        }
        public static Fraction FindClosest(double value, int maxDenominator)
        {
            Fraction result = new Fraction();
            double minDiff = 1;
            for (int i = 1; i <= maxDenominator; i++ )
            {
                Fraction f = Calculate(value, i);
                double diff = Math.Abs(f.ToDouble() - value);
                if (diff < minDiff)
                {
                    result = f;
                    minDiff = diff;
                }
            }
            return result;
        }
        private int numerator;

        public int Numerator
        {
            get { return numerator; }
            set { numerator = value; }
        }
        private int denominator;

        public int Denominator
        {
            get { return denominator; }
            set { denominator = value; }
        }
        private int integerPart;

        public int IntegerPart
        {
            get { return integerPart; }
            set { integerPart = value; }
        }




        public double ToDouble()
        {
            if (denominator == 0)
                throw new NotSupportedException();
            return integerPart + (double)numerator / denominator;
        }

        public override string ToString()
        {
            if (integerPart == 0 && numerator != 0)
                return fractionPart;
            return string.Format("{0} {1}", integerPart, fractionPart);
        }
        string fractionPart
        {
            get
            {
                if (numerator == 0)
                    return "   ";
                return string.Format("{0}/{1}", numerator, denominator);
            }
        }
    }
}
